package com.dynamic.mybatis.web.controller;

import com.alibaba.druid.pool.DruidDataSource;
import com.dynamic.mybatis.core.datasource.DataSourceProperty;
import com.dynamic.mybatis.core.datasource.DynamicMultipleDataSource;
import com.dynamic.mybatis.core.metadata.DynamicPage;
import com.dynamic.mybatis.core.parser.NamespaceHelper;
import com.dynamic.mybatis.core.session.DynamicSqlSessionTemplate;
import com.dynamic.mybatis.core.utils.BeanUtils;
import com.dynamic.mybatis.core.utils.StringUtils;
import com.dynamic.mybatis.web.vo.DataSourceVo;
import com.dynamic.mybatis.web.vo.QueryTableColumnDataSourceVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.sql.DataSource;
import java.sql.Connection;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Description
 * @Author xs
 * @Date 2023/3/22 12:08
 */
@RestController
@RequestMapping("/datasource/")
public class DataSourceController {
    @Autowired
    @Lazy
    private DynamicSqlSessionTemplate sqlSessionTemplate;


    @PostMapping("queryTableColumn")
    public Map<String, Map<String, List<String>>> queryTableColumn(@RequestBody List<QueryTableColumnDataSourceVo> dataSources) throws Exception {
        if (dataSources == null || dataSources.size() < 1) {
            return null;
        }
        Map<String, Connection> connections = new HashMap<>();
        for (QueryTableColumnDataSourceVo dataSource : dataSources) {
            String dataSourceKey = NamespaceHelper.getIdentity(dataSource.getNamespace(), dataSource.getCode());
            connections.put(dataSource.getCode(), sqlSessionTemplate.getConnectionByDataSourceKey(dataSourceKey));
        }
        return sqlSessionTemplate.getDynamicMappedStatementHelper().getMixedMappedStatementFieldParser().queryTableColumn(connections);
    }

    @PostMapping("queryTable")
    public List<String> queryTableColumn(String id) {
        Connection connection = sqlSessionTemplate.getConnectionByDataSourceKey(id);
        DataSourceProperty dataSourceProperty = sqlSessionTemplate.getDataSourceProperty(id);
        return sqlSessionTemplate.getDynamicMappedStatementHelper().getMixedMappedStatementFieldParser().queryTable(dataSourceProperty.getCode(), connection);
    }


    @RequestMapping("page")
    public DynamicPage page(DataSourceVo queryVo) {
        List<DataSourceVo> dmsList = filter(queryVo).skip((queryVo.getPageNumber() - 1) * queryVo.getPageSize()).limit(queryVo.getPageSize()).collect(Collectors.toList());
        long total = filter(queryVo).count();
        return queryVo.result(dmsList, total);
    }


    @RequestMapping("query")
    public List<DataSourceVo> queryDatasource(DataSourceVo queryVo) {
        return filter(queryVo).collect(Collectors.toList());
    }


    @RequestMapping("get")
    public DataSourceVo getById(@RequestBody DataSourceVo queryVo) {
        return filter(queryVo).findFirst().orElse(null);
    }


    private Stream<DataSourceVo> filter(DataSourceVo queryVo) {
        DynamicMultipleDataSource dynamicMultipleDataSource = (DynamicMultipleDataSource) sqlSessionTemplate.getSqlSession().getConfiguration().getEnvironment().getDataSource();
        Map<Object, DataSource> multipleDataSourceMap = dynamicMultipleDataSource.getDataSources();
        return multipleDataSourceMap.entrySet().stream().filter(d -> {
            DataSourceProperty property = dynamicMultipleDataSource.getProperty(d.getKey());
            if (property == null) {
                return Boolean.FALSE;
            } else if (StringUtils.isNotBlank(queryVo.getNamespace()) && !Objects.equals(property.getTenantCode(), queryVo.getNamespace())) {
                return Boolean.FALSE;
            } else if (StringUtils.isNotBlank(queryVo.getName()) && !Objects.equals(property.getName(), queryVo.getName())) {
                return Boolean.FALSE;
            } else if (StringUtils.isNotBlank(queryVo.getCode()) && !Objects.equals(property.getCode(), queryVo.getCode())) {
                return Boolean.FALSE;
            } else if (StringUtils.isNotBlank(queryVo.getDatabaseType()) && !Objects.equals(property.getDatabaseType(), queryVo.getDatabaseType())) {
                return Boolean.FALSE;
            } else if (StringUtils.isNotBlank(queryVo.getDatabaseName()) && !Objects.equals(property.getDatabaseName(), queryVo.getDatabaseName())) {
                return Boolean.FALSE;
            } else if (StringUtils.isNotBlank(queryVo.getUsername()) && !Objects.equals(property.getUsername(), queryVo.getUsername())) {
                return Boolean.FALSE;
            }
            return Boolean.TRUE;
        }).map(entry -> {
            DataSourceProperty property = dynamicMultipleDataSource.getProperty(entry.getKey());
            DataSourceVo dataSourceVo = new DataSourceVo();
            dataSourceVo.setId(NamespaceHelper.getIdentity(property.getTenantCode(), property.getCode()));
            dataSourceVo.setNamespace(property.getTenantCode());
            dataSourceVo.setName(property.getName());
            dataSourceVo.setDatabaseName(property.getDatabaseName());
            dataSourceVo.setCode(property.getCode());
            dataSourceVo.setDatabaseType(property.getDatabaseType());
            dataSourceVo.setUrl(property.getUrl());
            dataSourceVo.setUsername(property.getUsername());
            dataSourceVo.setPassword(property.getPassword());
            dataSourceVo.setDriverClass(property.getDriverClass());

            Map<Object, Object> attribute = dynamicMultipleDataSource.getAttributes(property.getCode());
            if (attribute != null) {
                dataSourceVo.setAttribute(attribute);
            }
            return dataSourceVo;
        });
    }


    @PostMapping("add")
    public void addDataSource(@RequestBody DataSourceVo dataSourceVo) throws Exception {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(dataSourceVo.getUrl());
        dataSource.setUsername(dataSourceVo.getUsername());
        dataSource.setPassword(dataSourceVo.getPassword());
        dataSource.setDriverClassName(dataSourceVo.getDriverClass());

        String datasourceKey = NamespaceHelper.getIdentity(dataSourceVo.getNamespace(), dataSourceVo.getCode());
        DataSourceProperty property = new DataSourceProperty();
        BeanUtils.copy(dataSourceVo, property);
        sqlSessionTemplate.addDataSource(datasourceKey, dataSource, property, dataSourceVo.getAttribute());
    }
}